package com.bracketbird.client.gui.club.tournament.rtc;


import com.bracketbird.client.gui.club.tournament.*;
import com.bracketbird.client.model.*;
import com.bracketbird.client.model.tournament.*;
import com.bracketbird.client.service.rtc.*;
import com.bracketbird.client.util.*;
import com.bracketbird.clientcore.appcontrol.*;

import java.util.*;

/**
 * All events originated from User interaction goes through this class.
 * <p/>
 * RTC also listens for relevant state changes events from the tournament to notify server about theese.
 */
public class RTC {

    private boolean reloading = false;

    //listeners for state events that should be notified to server.
    private TournamentListener<TournamentStateChangedEvent> tournamentStateListener = new TournamentListener<TournamentStateChangedEvent>() {
        public void onChange(TournamentStateChangedEvent event) {
            if (!event.isClientEvent()) {
                return;
            }
            TournamentState newState = event.getNewState();
            TournamentState oldState = event.getOldState();
            //server should not be notified if stateshift is between ready and notready.
            if ((newState.equals(new NotReady()) || newState.equals(new Ready())) && (oldState.equals(new NotReady()) || oldState.equals(new Ready()))) {
                return;
            }

            serverSync.stateChanged(event);
        }
    };

    private TournamentListener<LevelStateEvent> levelStateListener = new TournamentListener<LevelStateEvent>() {
        public void onChange(LevelStateEvent event) {
            if (!event.isClientEvent()) {
                return;
            }
            serverSync.stateChanged(event);
        }
    };


    private ServerEventQueue serverSync;
    private Tournament tournament;
    private static RTC instance;

    private RTC() {
    }

    public static RTC getInstance() {
        if (instance == null) {
            instance = new RTC();
        }
        return instance;
    }

    public void loadTournament(Tournament t) {
        this.tournament = t;
        tournament.addStateListener(tournamentStateListener);

        //init gui and set listeners
        initGuiListeners();
    }

    private void initGuiListeners() {
        TeamsPageController.getInstance().getPage();
        SettingsPageController.getInstance().getPage();
        EnterResultsPageController.getInstance().getPage();
        RankingViewPageController.getInstance().getPage();
    }

    public void loadServerSync(List<RTCEvent> eventLog) {
        serverSync = new ServerEventQueue(tournament.getId());
        serverSync.start(eventLog);
    }


    public Tournament getTournament() {
        return tournament;
    }

    private void tournamentFinished() {
        //TODO
    }


    //TEAMS

    public void addTeam(PlayingTeam team, boolean fromClient) {
        new AddTeamEventHandler(fromClient, team).handleEvent();
    }

    public void updateTeam(PlayingTeam team, PlayingTeamVO upt, boolean fromClient) {
        new UpdateTeamEventHandler(fromClient, team, upt).handleEvent();
    }

    public void deleteTeam(PlayingTeam team, boolean fromClient) {
        new DeleteTeamEventHandler(fromClient, team).handleEvent();
    }

    //LEVELS

    public void addLevel(final TournamentLevel level, boolean fromClient) {
        new AddLevelEventHandler(fromClient, level).handleEvent();
    }

    public void updateLevelSettings(final TournamentLevel level, final LevelSettings lu, final boolean fromClient) {
        new UpdateLevelEventHandler(fromClient, level, lu).handleEvent();
    }

    public void deleteLevel(TournamentLevel level, boolean fromClient) {
        new DeleteLevelEventHandler(fromClient, level).handleEvent();
    }

    //MATCHES

    public void layoutMatches(final TournamentLevel l, final boolean fromClient) {
        new LayoutMatchesEventHandler(fromClient, l).handleEvent();
    }

    public void updateMatch(TournamentLevel level, MatchVO updVO, boolean fromClient) {
        new UpdateMatchEventHandler(fromClient, level, updVO).handleEvent();
    }


    public void finished(TournamentLevel current, LevelFinishedVO vo, boolean fromClient) {
        new FinishedLevelEventHandler(fromClient, current, vo).handleEvent();

    }


    public void nameChanged(String value, boolean fromClient) {
        tournament.updateName(value, fromClient);
    }

    public void reLoadTournament(List<RTCEvent> allEvents) {
        RTCEventPrinter.printEvents(allEvents, "reLoadTournament");
        
        //throw away changes and bring client up to date
        Tournament t = new Tournament();
        t.setId(tournament.getId());
        t.setName(tournament.getName());
        tournament = t;
        tournament.addStateListener(tournamentStateListener);

        //clean gui
        clearGui();

        //will automatically reload the given events.
        loadServerSync(allEvents);
        //System.out.println("RELOADING TOURNAMENT end.");
    }

    private void clearGui() {
        TeamsPageController.getInstance().clear();
        SettingsPageController.getInstance().clear();
        EnterResultsPageController.getInstance().clear();
        RankingViewPageController.getInstance().clear();

        initGuiListeners();
        PageFlow.show(PageFlow.activeController);

    }

    public ServerEventQueue getServerSync() {
        return serverSync;
    }


    public void handleFailure(Throwable t, String message) {
            System.out.println("************* FAILURE ***********");

            if (message != null) {
                //System.out.println("Message: "+message);
            }
            if (t != null) {
                t.printStackTrace();
            }
        getServerSync();
/*

            //if an error (eg. handleFailure is called while reloading) all events until reloading can be berformed should be
            // deleted on server to ensure stability (eg. removing bad events on server).
            if (reloading) {
                //System.out.println("Handlefailure reloading = true");

                final List<RTCEvent> doneEvents = serverSync.getDoneEvents();
                RTCEventPrinter.printEvents(doneEvents, "DoneEvents (handleFailure; reloading = true)");
                if (doneEvents.isEmpty()) {
                    //System.out.println("Handlefailure doneevents is empty");

                    //TODO - show pop with text (Try to close down and open tournament again - if that doesn't work print tournament)
                    return;
                }
                else {
                    //System.out.println("Handlefailure doneEvents not empty");

                    //TODO - show pop with text (reloading tournament - latest changes may be lost. check it)
                    RTCEvent lastDone = CU.lastItem(doneEvents);
                    Service.deleteEventsAfter(new RTCDeleteEventsAction(lastDone), new CallBack<VoidResult>() {
                        @Override
                        public void success(VoidResult result) {
                            reloading = false;
                            reLoadTournament(doneEvents);
                        }

                        @Override
                        public void fail(Throwable t) {
                            t.printStackTrace();
                        }
                    });
                }
            }
            else {
                //System.out.println("Handlefailure reloading = false");

                reloading = true;
                //TODO - show pop with text
                reLoadTournament(serverSync.getDoneEvents());
                //System.out.println("Handlefailure End");

            }
        }
        finally {
            reloading = false;
        }
        */
    }

}
